<?php


namespace App\Common;
use App\Exceptions\BusinessException;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use InvalidArgumentException;
/**
 * jwt密钥生成解析类
 *
 * @package App\Http\Common
 */
class JwtAuth
{
    private static $instance;

    //私钥，没有私钥不会认证通过
    private $secret;
    //令牌的过期时间
    private $tokenTtl = Constant::JWT_TTL;
    private $token;
    private $userId;
    private $userName;
    private $issuer = 'himall.api.h5.service';
    private $audience  = 'himall.token';
    private $type;
    private $expiredAt;

    /**
     * 验证token
     *
     * @return array|bool
     */
    public function validate()
    {
        $token = $this->token;
        $parseData = [];
        try{
            $signer = new Sha256();
            if (!$token) {
                return false;
            }
            $parser = new Parser();
            $parse = $parser->parse($token);
            ////先验证私钥
            if ($parse->verify($signer, $this->secret) === false) {
                return $parseData;
            } else {
                $parseData = [
                    'entity_id' => $parse->getClaim("entity_id"),
                    'expired_at' => $parse->getClaim('exp'),
                    'type' => $parse->getClaim('type'),
                    'entity_name' => $parse->getClaim('entity_name')
                ];
            }
        }catch (InvalidArgumentException $e){
            return $parseData;
        }
        return $parseData;
    }

    /**
     * 生成 token
     *
     * @return $this
     * @throws BusinessException
     */
    public function encode()
    {
        try {
            $builder = new Builder();
            $signer = new Sha256();
            //发布端url颁发者
            $builder->setIssuer($this->issuer);
            //请求端URL访问群体
            $builder->setAudience($this->audience);
            //唯一的jwt id作为头项复制
            $builder->setId("hiyee.mall.server", true);
            //配置颁发令牌的时间
            $builder->setIssuedAt(time());
            //令牌可以使用的时间
            $builder->setNotBefore(time() + 5);
            //令牌的过期时间
            $ttl = time() + $this->tokenTtl;
            $builder->setExpiration($ttl);
            //配置一个名为“user_id”的新声明
            $builder->set("entity_id", $this->userId);
            $builder->set("entity_name", $this->userName);
            // 配置token类型的声明 客户、管理员
            $builder->set('type', $this->type);
            //使用“$this->secret”作为密钥创建签名
            $builder->sign($signer, $this->secret);
            //生成的令牌
            $token = $builder->getToken();
            if(empty($token)) {
                throw new \Exception('获取token失败');
            }
            $this->token = (string)$token;
            $this->expiredAt = $ttl; // 令牌生存时间
            return $this;
        } catch (\Exception $exception) {
            throw new BusinessException(ResponseCode::JWT_MAKE_FAIL);
        }
    }

    /**
     * 单例模式 禁止该类在外部被new
     *
     * JwtAuth constructor.
     */
    private function __construct()
    {
        $this->secret = env('JWT_SECRET', '000_111_222@123@#');
    }

    /**
     * 获取token
     *
     * @return string
     */
    public function getToken()
    {
        return $this->token;
    }

    /**
     * 设置token
     *
     * @param string $token
     * @return
     */
    public function setToken(string $token)
    {
        $this->token = $token;
        return $this;
    }

    /**
     * 设置token类型
     *
     * @param string $type
     * @return
     */
    public function setType(string $type)
    {
        $this->type = $type;
        return $this;
    }

    /**
     * 设置用户ID
     *
     * @param int $userId
     * @return
     */
    public function setUserId(int $userId)
    {
        $this->userId = $userId;
        return $this;
    }

    /**
     * @return mixed
     */
    public function getExpiredAt()
    {
        return $this->expiredAt;
    }

    /**
     * @param mixed $expiredAt
     */
    public function setExpiredAt($expiredAt): void
    {
        $this->expiredAt = $expiredAt;
    }

    /**
     * @return mixed
     */
    public function getUserName()
    {
        return $this->userName;
    }

    /**
     * @param mixed $userName
     */
    public function setUserName($userName)
    {
        $this->userName = $userName;
        return $this;
    }

    /**
     * 该类的实例
     *
     * @return JwtAuth
     */
    public static function getInstance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * 单例模式 禁止外部克隆
     */
    private function __clone(){}
}
